<!--
 * @Author: Xujianchen
 * @Date: 2024-09-12 09:55:34
 * @LastEditors: xujianchen
 * @LastEditTime: 2024-09-12 11:24:42
 * @Description: 验证码(方格式)
-->
<template>
  <div class="captcha">
    <div class="captcha-grid">
      <el-space :size="size">
        <div
          v-for="(char, index) in length"
          :key="index"
          :class="{ 'focused': isFocused(index) }"
          :style="itemStyle"
          class="captcha-box"
        >
          <input
            ref="captchaInputRef"
            v-model="captchaValues[index]"
            type="text"
            maxlength="1"
            class="captcha-input"
            @input="onInput(index)"
            @focus="onFocus(index)"
            @blur="onBlur(index)"
            @keydown="(event) => onKeyDown(index, event)"
          />
        </div>
      </el-space>
    </div>
  </div>
</template>

<script setup>
import { getCssPropertyValue } from '@/app/style'

const {
  length,
  valueToArray = false,
  activeColor = getCssPropertyValue('--el-color-primary'),
} = defineProps({
  length: {
    type: Number,
    default: 4,
  },
  itemStyle: {
    type: Object,
    default: () => ({}),
  },
  size: Number,
  activeColor: String,
  valueToArray: Boolean,
})
const emit = defineEmits(['complete', 'focus', 'blur'])

const captchaValues = ref(Array(length).fill(''))
const captchaInputRef = ref([])
const focusIndex = ref(-1)

function onInput(index) {
  const values = captchaValues.value
  const inputRef = captchaInputRef.value
  // 如果输入框不为空，自动聚焦下一个输入框
  if (values[index] && index < length - 1) {
    inputRef[index + 1].focus()
  } else if (index === length - 1) {
    // 到最后一位时
  }

  hasValues(values) && emit('complete', getValue())
}

function onKeyDown(index, event) {
  // 处理删除键，聚焦到前一个输入框
  if (event.key === 'Backspace') {
    const values = captchaValues.value
    const inputRef = captchaInputRef.value
    if (index === length - 1 && !values[index]) {
      // 如果是最后一个输入框且为空，聚焦到前一个输入框
      if (index > 0) {
        inputRef[index - 1].focus()
      }
    } else if (index > 0 && !values[index]) {
      // 如果当前输入框为空且不是第一个输入框，聚焦到前一个输入框
      inputRef[index - 1].focus()
    }
  }
}

function onFocus(index) {
  focusIndex.value = index
  emit('focus', index)
}

function onBlur(index) {
  if (index === focusIndex.value) {
    focusIndex.value = -1
  }
  emit('blur', index)
}

function getValue() {
  const values = captchaValues.value
  return valueToArray ? values : values?.join('')
}

function isFocused(index) {
  return focusIndex.value === index
}

function hasValues(arr) {
  return arr.every((item) => ![undefined, null, ''].includes(item))
}

defineExpose({ getValue })
</script>

<style scoped lang="scss">
.captcha {
  display: flex;

  &-grid {
    display: flex;
  }

  &-box {
    width: 30px;
    height: 30px;
    border-radius: 4px;
    padding: $space-small-s;
    border: 1px solid var(--el-border-color);
    background-color: var(--el-bg-color);
    transition: border-color 0.3s, box-shadow 0.3s, transform 0.3s;

    &:focus {
      outline: none;
    }

    &.focused {
      border-color: v-bind(activeColor);
      box-shadow: 0 0 3px v-bind(activeColor);
      transform: scale(1.05);

      input {
        color: v-bind(activeColor);
      }
    }
  }

  &-input {
    width: 100%;
    height: 100%;
    border: none;
    outline: none;
    text-align: center;
    font-size: $font-size-large-x;
    color: var(--el-text-color-regular);
  }
}
</style>
